#include <stdio.h>
#include <stdlib.h>

#define STATUS_ERROR -1
#define STATUS_OK 0
#define STATUS_EMEM 1
#define STATUS_ENULL 2
#define STATUS_ETOOLARGE 3
#define STATUS_NOTFOUND 4

typedef int DataType;

typedef struct node
{
	DataType data;
	struct node * next;
} Node;

typedef struct
{
	int length;
	Node * next;
} Head;

typedef Head * List;
typedef int Status;

Status init(List * first)
{
	*first = (Head *)malloc(sizeof(Head));
	if(*first == NULL)
	{
		return STATUS_EMEM;
	}

	(*first)->length = 0;
	(*first)->next = NULL;

	return STATUS_OK;
}

Status locate(List first, int index, Node ** p)
{
	int i;

	if(first == NULL)
	{
		return STATUS_ENULL;
	}

	if(index > first->length)
	{
		return STATUS_ETOOLARGE;
	}

	*p = first->next;

	for(i = 0; i < index; ++i)
	{
		if (*p != NULL)
		{
			*p = (*p)->next;
		}
	}

	return STATUS_OK;
}

Status insert(List first, DataType data, int index)
{
	Node * p, * q;

	if(first == NULL)
	{
		return STATUS_ENULL;
	}

	if(index > first->length)
	{
		return STATUS_ETOOLARGE;
	}
	
	q = (Node *)malloc(sizeof(Node));
	q->data = data;
	if(index == 0)
	{
		q->next = first->next;
		first->next = q;
	}
	else
	{
		if(locate(first, index - 1, &p) != STATUS_OK)
		{
			return STATUS_ERROR;
		}
		q->next = p->next;
		p->next = q;
	}

	first->length++;

	return STATUS_OK;
}

Status add(List first, DataType data)
{
	return insert(first, data, first->length);
}

Status del(List first, int index)
{
	Node * p, * q;

	if(first == NULL)
	{
		return STATUS_ENULL;
	}

	if(index >= first->length)
	{
		return STATUS_ETOOLARGE;
	}

	if(index == 0)
	{
		q = first->next;
		first->next = q->next;
		free(q);
		q = NULL;
	}
	else
	{
		if(locate(first, index - 1, &p) != STATUS_OK || p == NULL)
		{
			return STATUS_ERROR;
		}
		q = p->next;
		p->next = q->next;
		free(q);
		q = NULL;
	}

	first->length--;

	return STATUS_OK;
}

void test(const char * msg, Status st, Status code, int c)
{
	printf(msg);
	printf(" ... ");

	if(st == code)
	{
		printf("Success with code %d\n", st);
	}
	else
	{
		printf("Failed with code %d\n", st);
		if(c)
		{
			exit(st);
		}
	}
}

int main(void)
{
	List first = NULL;
	Node * p = NULL;
	int i;

	test("Init", init(&first), STATUS_OK, 1);
	test("Insert", insert(first, 10, 0), STATUS_OK, 0);
	test("Insert", insert(first, 20, 0), STATUS_OK, 0);
	test("Insert", insert(first, 15, 0), STATUS_OK, 0);
	test("Insert", insert(first, 25, 2), STATUS_OK, 0);
	test("Insert", insert(first, 1, 9), STATUS_ETOOLARGE, 0);
	test("Locate", locate(first, 0, &p), STATUS_OK, 0);
	if(p != NULL)
	{
		printf("p->data: %d\n", p->data);
	}
	printf("length: %d\n", first->length);
	test("Delete", del(first, 0), STATUS_OK, 0);
	printf("length: %d\n", first->length);

	for(i = 0; i < first->length; ++i)
	{
		locate(first, i, &p);
		printf("Index %d: %d\n", i, p->data);
	}

	return 0;
}